package rath.me2day.photo;

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.text.SimpleDateFormat;
import java.util.Date;

import net.me2day.java.Me2API;

import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;

import rath.util.Database;

/**
 *
 * @author Jang-Ho Hwang, rath@xrath.com
 * @version 1.0, $Id$ since 2007/06/05 1.1, 2007/06/07
 */
public class Server extends Thread {
	private static SimpleDateFormat fmtFile = new SimpleDateFormat(
			"yyyy-MM-dd-HH-mm-ss");
	private static SimpleDateFormat fmtDate = new SimpleDateFormat(
			"yyyy-MM-dd HH:mm:ss");

	private Socket socket = null;
	private DataInputStream in = null;
	private OutputStream out = null;

	private static PrintWriter log = null;

	public Server(Socket socket) throws IOException {
		this.socket = socket;
		in = new DataInputStream(socket.getInputStream());
		out = socket.getOutputStream();

		socket.setSoTimeout(20000);
	}

	public void run() {
		log("Connected from " + socket);
		try {
			// SKT/97972765
			String from = in.readUTF();
			String carrier = from.split("/")[0];
			String min = from.split("/")[1];
			String text = in.readUTF();

			text = text.replace('"', '\'');

			log("Identification << " + from);

			if (min.charAt(0) == '0')
				min = min.substring(1);

			// 여기서 carrier, min, text로 인증 체크를 한 후, 받을 필요가 없으면 끊어버리도록 한다.

			String username = null;
			String userkey = null;

			Connection con = null;
			PreparedStatement ps = null;
			ResultSet rs = null;
			try {
				con = Database.get();
				ps = con
						.prepareStatement("select username, userkey from me2day_photo where min like '%"
								+ min + "'");
				rs = ps.executeQuery();
				if (rs.next()) {
					username = rs.getString("username");
					userkey = rs.getString("userkey");
				}
			} finally {
				DbUtils.closeQuietly(con, ps, rs);
			}

			if (username == null) {
				log("Authentication failed (" + from + ")");
				throw new IllegalStateException("Unregistered Phone number ("
						+ from + ")");
			}

			log("Authenticated " + username + "/" + userkey);

			int size = in.readInt();

			log("Photo Upload request (size=" + size + ")");

			ByteArrayOutputStream bos = new ByteArrayOutputStream();

			byte[] buf = new byte[1200];
			int reads = 0;
			while (true) {
				int offset = 0;
				int readlen = 0;
				while (true) {
					readlen = in.read(buf, offset, buf.length - offset);
					if (readlen < 1)
						break;

					reads += readlen;
					if (readlen == 1200)
						break;
					offset += readlen;
					if (reads >= size)
						break;
				}
				out.write(1); // ACK

				bos.write(buf);
				System.out.print("#");
				System.out.flush();
				if (reads >= size)
					break;
				if (readlen == -1)
					break;
			}

			System.out.println();

			byte[] bImage = bos.toByteArray();

			if (bImage.length < size) {
				log("ERROR, Not enough image stream. aborted");
				throw new IOException("not enough image stream");
			}

			// 이제 파일로 저장하고, me2day_photo_data 테이블에 데이터를 넣어준다.

			File dir = new File(String.format("/home/rath/html-me2photo/%s",
					username));
			dir.mkdirs();
			File imageFile = new File(dir, fmtFile.format(new Date()) + ".jpg");

			FileOutputStream fos = new FileOutputStream(imageFile);
			fos.write(bImage);
			fos.flush();
			fos.close();

			uploadFile(username, imageFile.getName(), bImage);

			String url = String.format("http://me2photo.net/%s/%s", username,
					imageFile.getName());

			// 미투데이에 글 올리기.

			String eventTag = "";
			long now = System.currentTimeMillis();

			if (now > 1181358054276L && now < 1181484054276L)
				eventTag = " 미투백일잔치";

			String post = "\"" + text + "\":" + url;

			Me2API me2 = new Me2API();
			me2.setUsername(username);
			me2.setUserKey(userkey);
			me2.setApplicationKey("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
			me2.setSubscribeSMS(true);
			me2.post(post, "me2photo" + eventTag, Me2API.KIND_FEELING);

			String permalink = getPermaLink(me2.getLastResult());

			System.out.println("* New Photo! "
					+ String.format("(user=%s, url=%s, permalink=%s)",
							username, url, permalink));
			System.out.println(post);

			log("Complete with this content >> " + post);

			Database.doUpdate(
					"insert into me2day_photo_data value (?, ?, ?, ?, ?)",
					username, permalink, text, url, fmtDate.format(new Date()));
			Database
					.doUpdate(
							"update me2day_photo set post_count=post_count+1 where username=?",
							username);

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			close();
			log("Closed from " + socket);
		}
	}

	private String getPermaLink(String str) {
		if (str == null)
			return "";
		int i0 = str.indexOf("<permalink>");
		int i1 = str.indexOf("</permalink>");

		if (i0 == -1 || i1 == -1)
			return "";

		return str.substring(i0 + "<permalink>".length(), i1);
	}

	public void close() {
		if (out != null)
			try {
				out.close();
			} catch (IOException e) {
			}
		if (in != null)
			try {
				in.close();
			} catch (IOException e) {
			}
		if (socket != null)
			try {
				socket.close();
			} catch (IOException e) {
			}
	}

	private void uploadFile(String username, String filename, byte[] bImage)
			throws IOException {
		FTPClient ftp = null;
		try {
			ftp = new FTPClient();
			ftp.connect("xxxxxxx.xxx");
			ftp.login("xxxxx", "******");
			ftp.changeWorkingDirectory("******");

			ftp.makeDirectory(username);
			ftp.changeWorkingDirectory(username);

			ftp.setFileType(FTP.BINARY_FILE_TYPE);
			OutputStream out = ftp.storeFileStream(filename);
			out.write(bImage);
			out.flush();
			out.close();

			ftp.logout();
		} finally {
			if (ftp != null)
				ftp.disconnect();
		}
	}

	private static void log(String msg) {
		System.out.println(msg);
		log.println(String.format("[%s] %s", fmtDate.format(new Date()), msg));
	}

	public static void main(String[] args) throws Exception {
		FileOutputStream fos = new FileOutputStream("me2photo.log", true);
		log = new PrintWriter(new OutputStreamWriter(fos, "UTF-8"), true);

		ServerSocket socket = new ServerSocket(2212);
		log("me2photo service was started.");
		while (true) {
			Socket s = socket.accept();
			new Server(s).start();
		}
	}
}
